Added progressive animation loading. Added progressive animation loading.
authorJonathan Blandford <jrb@redhat.com>
Fri, 7 Jan 2000 18:29:13 +0000 (18:29 +0000)
committerJonathan Blandford <jrb@src.gnome.org>
Fri, 7 Jan 2000 18:29:13 +0000 (18:29 +0000)
2000-01-07  Jonathan Blandford  <jrb@redhat.com>

* gdk-pixbuf/gdk-pixbuf-io.c: Added progressive animation loading.
* gdk-pixbuf/gdk-pixbuf-io.h: Added progressive animation loading.
* gdk-pixbuf/gdk-pixbuf-loader.c: Added progressive animation
loading.
* gdk-pixbuf/gdk-pixbuf-loader.h: Added progressive animation
loading.
* gdk-pixbuf/io-gif.c (image_load_increment): I think the
ref-counting mess is finally fixed.  Added progressive animation
loading.

I think progressive animation loading all works now.  It's all
documented too, if anyone wants to play with it.

docs/reference/gdk-pixbuf/tmpl/rendering.sgml
gdk-pixbuf/ChangeLog
gdk-pixbuf/gdk-pixbuf-animation.c
gdk-pixbuf/gdk-pixbuf-io.h
gdk-pixbuf/gdk-pixbuf-loader.c
gdk-pixbuf/gdk-pixbuf-loader.h
gdk-pixbuf/io-gif.c
gdk-pixbuf/io-tiff.c
gtk/gdk-pixbuf-loader.c
gtk/gdk-pixbuf-loader.h

index a3f86c3701d9c27035e729dd92a5c1faa6453a12..09afa8c65900d93c985063f723b12fa9d1328bf8 100644 (file)
@@ -23,8 +23,11 @@ Rendering a pixbuf to a GDK drawable.
   <important>
     <para>
       Since these functions use GdkRGB for rendering, you must
-      initialize GdkRGB before using any of them.  You can do this by
-      calling gdk_rgb_init() near the beginning of your program.
+      initialize GdkRGB before using any of them.  If you are using
+      GNOME, gnome_init() will do this for you automatically.
+      Otherwise, you can do this by calling gdk_rgb_init() near the
+      beginning of your program.
+      
     </para>
   </important>
 
index 620cdf521024c90831168f40328b2fc73dc6536b..5d525cce41b098b1df96a5434598fa4d9a177a50 100644 (file)
@@ -1,5 +1,15 @@
 2000-01-07  Jonathan Blandford  <jrb@redhat.com>
 
+       * gdk-pixbuf/gdk-pixbuf-io.c: Added progressive animation loading.
+       * gdk-pixbuf/gdk-pixbuf-io.h: Added progressive animation loading.
+       * gdk-pixbuf/gdk-pixbuf-loader.c: Added progressive animation
+       loading.
+       * gdk-pixbuf/gdk-pixbuf-loader.h: Added progressive animation
+       loading.
+       * gdk-pixbuf/io-gif.c (image_load_increment): I think the
+       ref-counting mess is finally fixed.  Added progressive animation
+       loading. 
+
        * doc/tmpl/gdk-pixbuf-loader.sgml: much longer long description
        added. 
 
index 3a693cc968585c4d00deb71e7f40cfcffe409335..5e9e0d17e97391afd92cba251cb3cb636e7358dd 100644 (file)
@@ -98,7 +98,7 @@ gdk_pixbuf_animation_new_from_file (const char *filename)
                frame->delay_time = -1;
                frame->action = GDK_PIXBUF_FRAME_RETAIN;
 
-               animation = g_new (GdkPixbufAnimation, 1);
+               animation = g_new0 (GdkPixbufAnimation, 1);
                animation->ref_count = 1;
                animation->n_frames = 1;
                animation->frames = g_list_prepend (NULL, frame);
index e6ba541c02476c173fe49631009f5bcdb83dcfa8..4e439ce9b684d79e6975762f5f6130d6a647ec85 100644 (file)
@@ -44,8 +44,7 @@ typedef void (* ModuleUpdatedNotifyFunc) (GdkPixbuf *pixbuf,
                                          guint width, guint height,
                                          gpointer user_data);
 /* Needed only for animated images. */
-typedef void (* ModuleFrameDoneNotifyFunc) (GdkPixbuf *pixbuf,
-                                           gint frame,
+typedef void (* ModuleFrameDoneNotifyFunc) (GdkPixbufFrame *frame,
                                            gpointer user_data);
 typedef void (* ModuleAnimationDoneNotifyFunc) (GdkPixbuf *pixbuf,
                                                gpointer user_data);
index 69bb7f98ea8659c83b1ec1ea5f8cc058b684a626..56637df75d31611f523548b0da864f697bd3c00b 100644 (file)
@@ -35,6 +35,8 @@
 enum {
        AREA_UPDATED,
        AREA_PREPARED,
+       FRAME_DONE,
+       ANIMATION_DONE,
        CLOSED,
        LAST_SIGNAL
 };
@@ -89,11 +91,11 @@ gtk_marshal_NONE__INT_INT_INT_INT (GtkObject *object, GtkSignalFunc func, gpoint
 
 /**
  * gdk_pixbuf_loader_get_type:
- * @void: 
- * 
+ * @void:
+ *
  * Registers the #GdkPixubfLoader class if necessary, and returns the type ID
  * associated to it.
- * 
+ *
  * Return value: The type ID of the #GdkPixbufLoader class.
  **/
 GtkType
@@ -148,6 +150,22 @@ gdk_pixbuf_loader_class_init (GdkPixbufLoaderClass *class)
                                GTK_TYPE_INT,
                                GTK_TYPE_INT);
 
+       pixbuf_loader_signals[FRAME_DONE] =
+               gtk_signal_new ("frame_done",
+                               GTK_RUN_LAST,
+                               parent_class->type,
+                               GTK_SIGNAL_OFFSET (GdkPixbufLoaderClass, frame_done),
+                               gtk_marshal_NONE__NONE,
+                               GTK_TYPE_NONE, 0);
+
+       pixbuf_loader_signals[ANIMATION_DONE] =
+               gtk_signal_new ("animation_done",
+                               GTK_RUN_LAST,
+                               parent_class->type,
+                               GTK_SIGNAL_OFFSET (GdkPixbufLoaderClass, animation_done),
+                               gtk_marshal_NONE__NONE,
+                               GTK_TYPE_NONE, 0);
+
        pixbuf_loader_signals[CLOSED] =
                gtk_signal_new ("closed",
                                GTK_RUN_LAST,
@@ -186,6 +204,8 @@ gdk_pixbuf_loader_destroy (GtkObject *object)
        if (!priv->closed)
                gdk_pixbuf_loader_close (loader);
 
+       if (priv->animation)
+               gdk_pixbuf_animation_unref (priv->animation);
        if (priv->pixbuf)
                gdk_pixbuf_unref (priv->pixbuf);
 
@@ -236,14 +256,40 @@ gdk_pixbuf_loader_update (GdkPixbuf *pixbuf, guint x, guint y, guint width, guin
                         MIN (height, gdk_pixbuf_get_height (priv->pixbuf)));
 }
 
+static void
+gdk_pixbuf_loader_frame_done (GdkPixbufFrame *frame, gpointer loader)
+{
+       GdkPixbufLoaderPrivate *priv = NULL;
+
+       priv = GDK_PIXBUF_LOADER (loader)->private;
+
+       if (priv->animation == NULL) {
+               priv->animation = g_new0 (GdkPixbufAnimation, 1);
+               priv->animation->n_frames = 0;
+               priv->animation->ref_count = 1;
+       }
+
+       priv->animation->frames = g_list_append (priv->animation->frames, frame);
+       priv->animation->n_frames ++;
+       gtk_signal_emit (GTK_OBJECT (loader),
+                        pixbuf_loader_signals[FRAME_DONE],
+                        frame);
+}
+
+static void
+gdk_pixbuf_loader_animation_done (GdkPixbuf *pixbuf, gpointer loader)
+{
+       gtk_signal_emit (GTK_OBJECT (loader),
+                        pixbuf_loader_signals[ANIMATION_DONE]);
+}
+
 \f
 
 /**
  * gdk_pixbuf_loader_new:
- * @void: 
- * 
+ *
  * Creates a new pixbuf loader object.
- * 
+ *
  * Return value: A newly-created pixbuf loader.
  **/
 GdkPixbufLoader *
@@ -276,7 +322,11 @@ gdk_pixbuf_loader_load_module(GdkPixbufLoader *loader)
                return 0;
        }
 
-       priv->context = (*priv->image_module->begin_load) (gdk_pixbuf_loader_prepare, gdk_pixbuf_loader_update, NULL, NULL, loader);
+       priv->context = (*priv->image_module->begin_load) (gdk_pixbuf_loader_prepare,
+                                                          gdk_pixbuf_loader_update,
+                                                          gdk_pixbuf_loader_frame_done,
+                                                          gdk_pixbuf_loader_animation_done,
+                                                          loader);
 
        if (priv->context == NULL) {
                g_warning("Failed to begin progressive load");
@@ -285,7 +335,7 @@ gdk_pixbuf_loader_load_module(GdkPixbufLoader *loader)
 
        if( (* priv->image_module->load_increment) (priv->context, priv->header_buf, priv->header_buf_offset) )
                return priv->header_buf_offset;
+
        return 0;
 }
 
@@ -297,9 +347,9 @@ gdk_pixbuf_loader_eat_header_write (GdkPixbufLoader *loader, const guchar *buf,
 
        nbytes = MIN(LOADER_HEADER_SIZE - priv->header_buf_offset, count);
        memcpy (priv->header_buf + priv->header_buf_offset, buf, nbytes);
-           
+
        priv->header_buf_offset += nbytes;
-           
+
        if(priv->header_buf_offset >= LOADER_HEADER_SIZE) {
                if (gdk_pixbuf_loader_load_module(loader) == 0)
                        return 0;
@@ -385,11 +435,12 @@ gdk_pixbuf_loader_get_pixbuf (GdkPixbufLoader *loader)
 /**
  * gdk_pixbuf_loader_get_animation:
  * @loader: A pixbuf loader
- * 
+ *
  * Queries the GdkPixbufAnimation that a pixbuf loader is currently creating.
  * In general it only makes sense to call this function afer the "area_prepared"
- * signal has been emitted by the loader.
- * 
+ * signal has been emitted by the loader.  If the image is not an animation,
+ * then it will return NULL.
+ *
  * Return value: The GdkPixbufAnimation that the loader is loading, or NULL if
  not enough data has been read to determine the information.
  **/
@@ -438,3 +489,4 @@ gdk_pixbuf_loader_close (GdkPixbufLoader *loader)
        gtk_signal_emit (GTK_OBJECT (loader),
                         pixbuf_loader_signals[CLOSED]);
 }
+
index bbab22e11e4496a4c23b742d7453c7ab2b49d66b..9f9a79dc25407df69ab0b1931c861ecd57186065 100644 (file)
@@ -61,7 +61,7 @@ struct _GdkPixbufLoaderClass {
        void (* area_updated)    (GdkPixbufLoader *loader,
                                   guint x, guint y, guint width, guint height);
 
-       void (* frame_done)      (GdkPixbufLoader *loader, gint frame);
+       void (* frame_done)      (GdkPixbufLoader *loader, GdkPixbufFrame *frame);
 
        void (* animation_done)  (GdkPixbufLoader *loader);
 
index 13a66cfba4769e3a9775385e416e0006ef0f4160..1ba894dda681697e2ef8657eb079714cc1af2359 100644 (file)
@@ -42,6 +42,7 @@
  * -2 -> failure; abort the load
  * -3 -> control needs to be passed back to the main loop
  *        \_ (most of the time returning 0 will get this, but not always)
+ *
  * >1 -> for functions that get a guchar, the char will be returned.
  *
  * -jrb (11/03/1999)
@@ -129,6 +130,8 @@ struct _GifContext
        /* progressive read, only. */
        ModulePreparedNotifyFunc prepare_func;
        ModuleUpdatedNotifyFunc update_func;
+       ModuleFrameDoneNotifyFunc frame_done_func;
+       ModuleAnimationDoneNotifyFunc anim_done_func;
        gpointer user_data;
        guchar *buf;
        guint ptr;
@@ -670,7 +673,7 @@ gif_get_lzw (GifContext *context)
 
                if (context->prepare_func)
                        (* context->prepare_func) (context->pixbuf, context->user_data);
-               if (context->animation) {
+               if (context->animation || context->frame_done_func) {
                        context->frame = g_new (GdkPixbufFrame, 1);
                        context->frame->x_offset = 0;
                        context->frame->y_offset = 0;
@@ -691,8 +694,10 @@ gif_get_lzw (GifContext *context)
                                break;
                        }
                        context->frame->pixbuf = context->pixbuf;
-                       context->animation->n_frames ++;
-                       context->animation->frames = g_list_append (context->animation->frames, context->frame);
+                       if (context->animation) {
+                               context->animation->n_frames ++;
+                               context->animation->frames = g_list_append (context->animation->frames, context->frame);
+                       }
                }
        }
        dest = gdk_pixbuf_get_pixels (context->pixbuf);
@@ -816,6 +821,10 @@ gif_get_lzw (GifContext *context)
        }
 
        if (context->animation && context->state == GIF_GET_NEXT_STEP) {
+               (* context->frame_done_func) (context->frame,
+                                             context->user_data);
+
+               gdk_pixbuf_unref (context->pixbuf);
                context->pixbuf = NULL;
                context->frame = NULL;
        }
@@ -1059,6 +1068,8 @@ new_context (void)
        context->state = GIF_START;
        context->prepare_func = NULL;
        context->update_func = NULL;
+       context->frame_done_func = NULL;
+       context->anim_done_func = NULL;
        context->user_data = NULL;
        context->buf = NULL;
        context->amount_needed = 0;
@@ -1099,6 +1110,8 @@ image_begin_load (ModulePreparedNotifyFunc prepare_func,
        context = new_context ();
        context->prepare_func = prepare_func;
        context->update_func = update_func;
+       context->frame_done_func = frame_done_func;
+       context->anim_done_func = anim_done_func;
        context->user_data = user_data;
 
        return (gpointer) context;
@@ -1113,7 +1126,9 @@ image_stop_load (gpointer data)
 
        if (context->pixbuf)
                gdk_pixbuf_unref (context->pixbuf);
-/*     g_free (context->buf); */
+       if (context->animation)
+               gdk_pixbuf_animation_unref (context->animation);
+/*     g_free (context->buf);*/
        g_free (context);
 }
 
index 155a035778c50d57b99112d0e3d5f2987f6ebda4..a45a0b1149b9389171b8eba947acfff442a0b658 100644 (file)
@@ -5,6 +5,7 @@
  *
  * Authors: Mark Crichton <crichton@gimp.org>
  *          Federico Mena-Quintero <federico@gimp.org>
+ *          Jonathan Blandford <jrb@redhat.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -110,8 +111,8 @@ image_load_real (FILE *f, TiffData *context)
        TIFFClose (tiff);
 
        if (context) {
-               gdk_pixbuf_unref (pixbuf);
                (* context->update_func) (pixbuf, 0, 0, w, h, context->user_data);
+               gdk_pixbuf_unref (pixbuf);
        }
 
        return pixbuf;
index 69bb7f98ea8659c83b1ec1ea5f8cc058b684a626..56637df75d31611f523548b0da864f697bd3c00b 100644 (file)
@@ -35,6 +35,8 @@
 enum {
        AREA_UPDATED,
        AREA_PREPARED,
+       FRAME_DONE,
+       ANIMATION_DONE,
        CLOSED,
        LAST_SIGNAL
 };
@@ -89,11 +91,11 @@ gtk_marshal_NONE__INT_INT_INT_INT (GtkObject *object, GtkSignalFunc func, gpoint
 
 /**
  * gdk_pixbuf_loader_get_type:
- * @void: 
- * 
+ * @void:
+ *
  * Registers the #GdkPixubfLoader class if necessary, and returns the type ID
  * associated to it.
- * 
+ *
  * Return value: The type ID of the #GdkPixbufLoader class.
  **/
 GtkType
@@ -148,6 +150,22 @@ gdk_pixbuf_loader_class_init (GdkPixbufLoaderClass *class)
                                GTK_TYPE_INT,
                                GTK_TYPE_INT);
 
+       pixbuf_loader_signals[FRAME_DONE] =
+               gtk_signal_new ("frame_done",
+                               GTK_RUN_LAST,
+                               parent_class->type,
+                               GTK_SIGNAL_OFFSET (GdkPixbufLoaderClass, frame_done),
+                               gtk_marshal_NONE__NONE,
+                               GTK_TYPE_NONE, 0);
+
+       pixbuf_loader_signals[ANIMATION_DONE] =
+               gtk_signal_new ("animation_done",
+                               GTK_RUN_LAST,
+                               parent_class->type,
+                               GTK_SIGNAL_OFFSET (GdkPixbufLoaderClass, animation_done),
+                               gtk_marshal_NONE__NONE,
+                               GTK_TYPE_NONE, 0);
+
        pixbuf_loader_signals[CLOSED] =
                gtk_signal_new ("closed",
                                GTK_RUN_LAST,
@@ -186,6 +204,8 @@ gdk_pixbuf_loader_destroy (GtkObject *object)
        if (!priv->closed)
                gdk_pixbuf_loader_close (loader);
 
+       if (priv->animation)
+               gdk_pixbuf_animation_unref (priv->animation);
        if (priv->pixbuf)
                gdk_pixbuf_unref (priv->pixbuf);
 
@@ -236,14 +256,40 @@ gdk_pixbuf_loader_update (GdkPixbuf *pixbuf, guint x, guint y, guint width, guin
                         MIN (height, gdk_pixbuf_get_height (priv->pixbuf)));
 }
 
+static void
+gdk_pixbuf_loader_frame_done (GdkPixbufFrame *frame, gpointer loader)
+{
+       GdkPixbufLoaderPrivate *priv = NULL;
+
+       priv = GDK_PIXBUF_LOADER (loader)->private;
+
+       if (priv->animation == NULL) {
+               priv->animation = g_new0 (GdkPixbufAnimation, 1);
+               priv->animation->n_frames = 0;
+               priv->animation->ref_count = 1;
+       }
+
+       priv->animation->frames = g_list_append (priv->animation->frames, frame);
+       priv->animation->n_frames ++;
+       gtk_signal_emit (GTK_OBJECT (loader),
+                        pixbuf_loader_signals[FRAME_DONE],
+                        frame);
+}
+
+static void
+gdk_pixbuf_loader_animation_done (GdkPixbuf *pixbuf, gpointer loader)
+{
+       gtk_signal_emit (GTK_OBJECT (loader),
+                        pixbuf_loader_signals[ANIMATION_DONE]);
+}
+
 \f
 
 /**
  * gdk_pixbuf_loader_new:
- * @void: 
- * 
+ *
  * Creates a new pixbuf loader object.
- * 
+ *
  * Return value: A newly-created pixbuf loader.
  **/
 GdkPixbufLoader *
@@ -276,7 +322,11 @@ gdk_pixbuf_loader_load_module(GdkPixbufLoader *loader)
                return 0;
        }
 
-       priv->context = (*priv->image_module->begin_load) (gdk_pixbuf_loader_prepare, gdk_pixbuf_loader_update, NULL, NULL, loader);
+       priv->context = (*priv->image_module->begin_load) (gdk_pixbuf_loader_prepare,
+                                                          gdk_pixbuf_loader_update,
+                                                          gdk_pixbuf_loader_frame_done,
+                                                          gdk_pixbuf_loader_animation_done,
+                                                          loader);
 
        if (priv->context == NULL) {
                g_warning("Failed to begin progressive load");
@@ -285,7 +335,7 @@ gdk_pixbuf_loader_load_module(GdkPixbufLoader *loader)
 
        if( (* priv->image_module->load_increment) (priv->context, priv->header_buf, priv->header_buf_offset) )
                return priv->header_buf_offset;
+
        return 0;
 }
 
@@ -297,9 +347,9 @@ gdk_pixbuf_loader_eat_header_write (GdkPixbufLoader *loader, const guchar *buf,
 
        nbytes = MIN(LOADER_HEADER_SIZE - priv->header_buf_offset, count);
        memcpy (priv->header_buf + priv->header_buf_offset, buf, nbytes);
-           
+
        priv->header_buf_offset += nbytes;
-           
+
        if(priv->header_buf_offset >= LOADER_HEADER_SIZE) {
                if (gdk_pixbuf_loader_load_module(loader) == 0)
                        return 0;
@@ -385,11 +435,12 @@ gdk_pixbuf_loader_get_pixbuf (GdkPixbufLoader *loader)
 /**
  * gdk_pixbuf_loader_get_animation:
  * @loader: A pixbuf loader
- * 
+ *
  * Queries the GdkPixbufAnimation that a pixbuf loader is currently creating.
  * In general it only makes sense to call this function afer the "area_prepared"
- * signal has been emitted by the loader.
- * 
+ * signal has been emitted by the loader.  If the image is not an animation,
+ * then it will return NULL.
+ *
  * Return value: The GdkPixbufAnimation that the loader is loading, or NULL if
  not enough data has been read to determine the information.
  **/
@@ -438,3 +489,4 @@ gdk_pixbuf_loader_close (GdkPixbufLoader *loader)
        gtk_signal_emit (GTK_OBJECT (loader),
                         pixbuf_loader_signals[CLOSED]);
 }
+
index bbab22e11e4496a4c23b742d7453c7ab2b49d66b..9f9a79dc25407df69ab0b1931c861ecd57186065 100644 (file)
@@ -61,7 +61,7 @@ struct _GdkPixbufLoaderClass {
        void (* area_updated)    (GdkPixbufLoader *loader,
                                   guint x, guint y, guint width, guint height);
 
-       void (* frame_done)      (GdkPixbufLoader *loader, gint frame);
+       void (* frame_done)      (GdkPixbufLoader *loader, GdkPixbufFrame *frame);
 
        void (* animation_done)  (GdkPixbufLoader *loader);